/**
 * Program: Solo, a computer solitarie card game.
 * By: MD, md@tomatesasesinos.com
 * Copyright 2007
 *
 * License: GPL http://www.gnu.org/licences/gpl.html
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 *
 *
 * File: solo.c
 * Contents: The main program
 */

#include "globals.h"

int main(int argc, char *argv[])
{
	startGame();
	
	solitaireSDL();
	
	return 0;
}

void startGame(void)
{
	int iterator0, iterator1;
	
	//Start the random seed
	srand(time(0));
	
	//Fill the deck
	for (iterator0 = 0; iterator0 < NUM_CARDS_IN_DECK; iterator0++)
		deck[iterator0] = iterator0;
	
	//Clean the board
	for (iterator0 = 0; iterator0 < NUM_BOARD_PLACES; iterator0++)
	{
		numCardsBoardZones[iterator0] = 0;
		for (iterator1 = 0; iterator1 < NUM_CARDS_IN_DECK; iterator1++)
			board[iterator0][iterator1].numCard = NO_CARD;
	}
	
	dealCards();
}

void dealCards(void)
{
	int numCardsDeal;
	int countCardInDeck;
	int card;
	int extractPosition;
	//There is all the piles of cards on board.
	int pilesCardInBoard[NUM_BOARD_PLACES];
		pilesCardInBoard[PILE_DRAW_OUT] = 24;
		pilesCardInBoard[PILE_CARDS_DRAW] = 0;
		pilesCardInBoard[PILE_SUIT1] = 0;
		pilesCardInBoard[PILE_SUIT2] = 0;
		pilesCardInBoard[PILE_SUIT3] = 0;
		pilesCardInBoard[PILE_SUIT4] = 0;
		pilesCardInBoard[COLUMN1] = 1;
		pilesCardInBoard[COLUMN2] = 2;
		pilesCardInBoard[COLUMN3] = 3;
		pilesCardInBoard[COLUMN4] = 4;
		pilesCardInBoard[COLUMN5] = 5;
		pilesCardInBoard[COLUMN6] = 6;
		pilesCardInBoard[COLUMN7] = 7;
		pilesCardInBoard[HAND] = 0;
	
	//FALSE for no face up card in this zone and TRUE for face down card
	int zonesBoardFaceUpCard[NUM_BOARD_PLACES];
		zonesBoardFaceUpCard[PILE_DRAW_OUT] = FALSE;
		zonesBoardFaceUpCard[PILE_CARDS_DRAW] = FALSE;
		zonesBoardFaceUpCard[PILE_SUIT1] = FALSE;
		zonesBoardFaceUpCard[PILE_SUIT2] = FALSE;
		zonesBoardFaceUpCard[PILE_SUIT3] = FALSE;
		zonesBoardFaceUpCard[PILE_SUIT4] = FALSE;
		zonesBoardFaceUpCard[COLUMN1] = TRUE;
		zonesBoardFaceUpCard[COLUMN2] = TRUE;
		zonesBoardFaceUpCard[COLUMN3] = TRUE;
		zonesBoardFaceUpCard[COLUMN4] = TRUE;
		zonesBoardFaceUpCard[COLUMN5] = TRUE;
		zonesBoardFaceUpCard[COLUMN6] = TRUE;
		zonesBoardFaceUpCard[COLUMN7] = TRUE;
		zonesBoardFaceUpCard[HAND] = FALSE;
	
	//The position of cursor in the board
	int boardPosition = PILE_DRAW_OUT;
	
	
	
	for (numCardsDeal = 0; numCardsDeal < NUM_CARDS_IN_DECK; numCardsDeal++)
	{
		countCardInDeck = NUM_CARDS_IN_DECK - numCardsDeal;
		
		/*DEBUGING*/
		/*card = numCardsDeal;*/
		/**/
		if (countCardInDeck > 1) extractPosition = rand() % countCardInDeck; // Always extract between cards rest in deck
		else extractPosition = 0; //or extract the last card
		card = extractCardToDeck(extractPosition);
		/**/
		
		/*Put face down the cards in the piles, but if it is the last card to put, it see to put face up or face down.*/
		if (pilesCardInBoard[boardPosition] == 1)
		{
			//for the last card or one card in this pile
			if (zonesBoardFaceUpCard[boardPosition]) putCardInZone(boardPosition,card,FACE_UP);
			else putCardInZone(boardPosition,card,FACE_DOWN);
		}
		else putCardInZone(boardPosition,card,FACE_DOWN);
		pilesCardInBoard[boardPosition]--;
		
		
		//The code is for zones in board that don't need card because is a empy zone or the zone is fill, then move next zone and
		//check again for move again
		if (pilesCardInBoard[boardPosition] == 0)
		{
			while((boardPosition<13)&&(pilesCardInBoard[boardPosition]==0)) boardPosition++;
		}
	}
}

/*ExtractCardToDect extract card the deck in the pos parameter. Remove the card move the next card and add in final NO_CARD

  Example:
	  Deck = [ 1, 2, 3, 4 ] and pos = 2
	  before extractCardToDeck
	  [ 1, 2, 4, NO_CARD ]
  */
int extractCardToDeck(int pos)
{
	int returnCard = deck[pos];
	int iterator;
	
	for (iterator = pos; iterator < NUM_CARDS_IN_DECK - 1; iterator++)
	{
		deck[iterator] = deck[iterator + 1];
	}
	deck[iterator] = NO_CARD;
	
	return returnCard;
}

void extractCardPileDrawOut(void)
{
	putCardInZone(PILE_CARDS_DRAW,board[PILE_DRAW_OUT][0].numCard,FACE_UP);
	deleteFirstPositionZone(PILE_DRAW_OUT);
}

void deleteFirstPositionZone(int posInBoard)
{
	int iterator;

	if ((posInBoard >= COLUMN1) && (board[posInBoard][0].faceCard == FACE_UP))
		numCardsFaceUpInZone[posInBoard - COLUMN1]--;

	for (iterator = 0; iterator < (NUM_CARDS_IN_DECK - 1); iterator++)
	{
		board[posInBoard][iterator] = board[posInBoard][iterator + 1];
	}
	board[posInBoard][NUM_CARDS_IN_DECK - 1].numCard = NO_CARD;
	numCardsBoardZones[posInBoard]--;
}

void refillPileDrawOut(void)
{
	int iterator;

	/* It's diferent the positions in a matrix than the count of positions (in C because the first is [0] )
	and for 3 elements there are 0,1 and 3 positions in the matrix because numCardsBoardZones[PILE_CARDS_DRAW]
	use < in the for loop and -1 in the operations*/

	for(iterator = 0; iterator < numCardsBoardZones[PILE_CARDS_DRAW]; iterator++)
	{
		board[PILE_DRAW_OUT][numCardsBoardZones[PILE_CARDS_DRAW] - 1 - iterator].numCard = board[PILE_CARDS_DRAW][iterator].numCard;
		board[PILE_DRAW_OUT][numCardsBoardZones[PILE_CARDS_DRAW] - 1 - iterator].faceCard = FACE_DOWN;
		board[PILE_CARDS_DRAW][iterator].numCard = NO_CARD;
	}
	numCardsBoardZones[PILE_DRAW_OUT] = numCardsBoardZones[PILE_CARDS_DRAW];
	numCardsBoardZones[PILE_CARDS_DRAW] = 0;
}

void moveCard(int origin,int destiny)
{
	putCardInZone(destiny, board[origin][0].numCard, FACE_UP);
	deleteFirstPositionZone(origin);
}

void legalMoveCard(int origin,int destiny)
{
	int originCard = board[origin][0].numCard;
	int originCardSuit = originCard / NUM_CARDS_IN_SUIT;
	int originNumCardInSuit = originCard % NUM_CARDS_IN_SUIT; //Num write in card of suit.

	int destinyCard = board[destiny][0].numCard;
	int destinyCardSuit = destinyCard / NUM_CARDS_IN_SUIT;
	int destinyNumCardInSuit = destinyCard % NUM_CARDS_IN_SUIT; //Num write in card of suit.

	int legal = FALSE;

	//For move in the suit piles and NO_CARD + 1 == Ace (first card in suit) or previus card
	if ( (destiny < END_PILES) && ((destinyNumCardInSuit + 1) == originNumCardInSuit))
	{
		if (destinyNumCardInSuit == NO_CARD) legal = TRUE; //It's a empty pile.
		else
		{
			if (originCardSuit == destinyCardSuit) legal = TRUE; //Or it's the same suit in this destiny pile.
		}
	}
	else
	{
		if ((board[destiny][0].numCard == NO_CARD) && (originNumCardInSuit == KING_CARD))
			legal = TRUE; //Move king to stair pile empty
		else
		{
			if ((board[destiny][0].faceCard == FACE_DOWN) && (originNumCardInSuit == KING_CARD))
				legal=TRUE; //Or move king to stair empty but some card face down
			else
			{
				/*
				There are 4 suit:
					0º) clubs = black
					1º) heards = red
					2º)spades = black
					3º)diamonds = red

				In solitary it's legal move card to pile stair when
				previus card is black and card is red, or contrary form (red - black). And of course the previus
				card is one more that card to move.

				And in this code numSuit between 0, 1, 2, 3 and is black, red, black, red
				then the pairs is red and impair black, and mod 2 return for all number (in this case 0 to 3)
				0 pair and 1 pair. Well, if originSuit mod 2 = destinySuit mod it's same color and ilegal move.
				*/
				if (((originCardSuit % 2) != (destinyCardSuit % 2)) &&
					((originNumCardInSuit + 1) == destinyNumCardInSuit))
					legal = TRUE;
			}
		}
	}

	if (legal) moveCard(origin,destiny);
}

void legalMoveGroupCards(int origin, int positionInStairFaceUp, int destiny)
{
	int originFirstCardInGroup = board[origin][positionInStairFaceUp].numCard;
	int originFirstCardInGroupSuit = originFirstCardInGroup / NUM_CARDS_IN_SUIT;
	int originNumFirstCardInGroupInSuit = originFirstCardInGroup % NUM_CARDS_IN_SUIT; //Num write in card of suit.

	int destinyCard = board[destiny][0].numCard;
	int destinyCardSuit = destinyCard / NUM_CARDS_IN_SUIT;
	int destinyNumCardInSuit = destinyCard % NUM_CARDS_IN_SUIT; //Num write in card of suit.

	int legal = FALSE;

	int iterator;

	if (destiny >= COLUMN1) //Don't move group cards in stair to pile suits, then destiny must column1 or more.
	{
		//If the colummn is empty or facedown the top card and the first card is king, it's legal move.
		if (((destinyCard == NO_CARD) || (board[destiny][0].faceCard == FACE_DOWN)) &&
			(originNumFirstCardInGroupInSuit == KING_CARD)) legal = TRUE;
		else
		{
			//For legal move there are previus card one minor number and black when red or red when black.
			if (((originFirstCardInGroupSuit % 2) != (destinyCardSuit % 2)) &&
				((originNumFirstCardInGroupInSuit + 1) == destinyNumCardInSuit)) legal = TRUE;
		}
	}

	if (legal)
	{
		for (iterator = positionInStairFaceUp; iterator >=0; iterator--)
			putCardInZone(destiny,board[origin][iterator].numCard,FACE_UP);
		for (iterator = 0;iterator <= positionInStairFaceUp; iterator++)
			deleteFirstPositionZone(origin);
	}
}

int moveCardToPileSuit(int zoneBoard)
{
	int returnValue = FALSE;
	int numCard = board[zoneBoard][0].numCard; //take the first card in this zone board.
	int cardSuit = numCard / NUM_CARDS_IN_SUIT;
	int numCardInSuit = numCard % NUM_CARDS_IN_SUIT; //Num write in card of suit.
	int iterator;

	//Search for empty pile suit or pile suit that previus card for moving card.
	for (iterator = PILE_SUIT1; iterator < END_PILES; iterator++)
	{
		//It's not ace card.
		if (numCardInSuit > 0)
		{
			if ((board[iterator][0].numCard / NUM_CARDS_IN_SUIT) == cardSuit) //It's is the same suit
			{
				//If the last card in top pile suit is the previus to moving card, stop search.
				if ((board[iterator][0].numCard % NUM_CARDS_IN_SUIT) + 1 == numCardInSuit) break;
			}
		}
		else //If it's ace card, then search empty pile suit and stop search.
		{
			if (board[iterator][0].numCard == NO_CARD) break;
		}

	}

	/*
	If the iterator stop before end of piles suit, the searching look the empty pile suit
	or corret pile suit, and move the card to this pile suit.
	*/
	if (iterator != END_PILES)
	{
		moveCard(zoneBoard,iterator);

		returnValue = TRUE;
	}

	return returnValue;
}

void putCardInZone(int zoneBoard, int card, int faceCard)
{
	makeSpaceInFirstPositionZone(zoneBoard);
	board[zoneBoard][0].numCard = card;
	board[zoneBoard][0].faceCard = faceCard;
	numCardsBoardZones[zoneBoard]++;

	//If zone is between COLUMN1 AND COLUMN7 and the face of card is up then count card face up.
	if ((zoneBoard >= COLUMN1) && (faceCard == FACE_UP)) numCardsFaceUpInZone[zoneBoard - COLUMN1]++;
}

/*
 * As 52 positions in any zone never overflow with cards, The procedure move the cards for to clean first position.
 */
void makeSpaceInFirstPositionZone(int zoneBoard)
{
	int i;

	/*it's -2 because the limit or last value in array board is board[...][51] then
	with i = 50 the next line is board[zoneBoard][51] = board[zoneBoard][50];*/
	for(i = (NUM_CARDS_IN_DECK - 2); i >= 0; i--)
	{
		board[zoneBoard][i + 1] = board[zoneBoard][i];
	}
	board[zoneBoard][0].faceCard = FACE_UP;
	board[zoneBoard][0].numCard = NO_CARD;
}

/**
 * Check if the pile of cards is full.
 * 
 * @return The constant value TRUE is a win or FALSE is not win.
 */
int win(void)
{
	int returnValue = TRUE;
	int iterator;

	//Start with a true posibility to search if there are all king's card in the suit piles.
	for(iterator = PILE_SUIT1; iterator < END_PILES; iterator++)
	{
		if (board[iterator][0].numCard % NUM_CARDS_IN_SUIT != KING_CARD) returnValue = FALSE;
	}

	return returnValue;
}
